package com.explorex.infra.puma.gateway.netty.ws.message.handler;

import com.explorex.infra.puma.adaptor.LongLinkImAdaptor;
import com.explorex.infra.puma.gateway.netty.common.SpringContextUtils;
import com.explorex.infra.puma.gateway.netty.common.utils.JacksonObjectMapper;
import com.explorex.infra.puma.gateway.netty.ws.WebSocketSession;
import com.explorex.infra.puma.gateway.netty.ws.enums.MessageTypeEnum;
import com.explorex.infra.puma.gateway.netty.ws.message.Message;
import com.explorex.infra.puma.gateway.netty.ws.message.MessageBody;
import com.explorex.infra.puma.gateway.netty.ws.message.MessageHeader;
import com.explorex.infra.puma.gateway.netty.ws.message.RespMessageBody;
import com.fasterxml.jackson.databind.JsonNode;

import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * @author: JacceYang
 * @createTime: 2022/07/19 2:29 下午
 * @description: 常规消息类型的消息处理器
 */
@Slf4j
public class MessageTypeProcessor extends AbstractBaseProcessor {
    private static final ExecutorService threadPoolExecutor = Executors.newCachedThreadPool();

    private final String SERVER_EXCEPTION = "service exception";

    private LongLinkImAdaptor longLinkImAdaptor=SpringContextUtils.getBean("longLinkImAdaptor",LongLinkImAdaptor.class);


    public static Message buildAck(byte[] response, MessageHeader reqHeader, String uuid) {
        return buildAck(response, reqHeader, 0, "success", uuid);
    }

    public static Message buildAck(byte[] response, MessageHeader reqHeader, int code, String msg, String uuid) {
        Message message = new Message();
        MessageTypeMessageAck messageAck = new MessageTypeMessageAck();
        messageAck.setUuid(uuid);
        messageAck.setCode(code);
        messageAck.setMsg(msg);
        messageAck.setTs(System.currentTimeMillis());

        if (response != null && response.length > 0) {
            messageAck.setData(new String(response));
        }

        MessageHeader respHeader = new MessageHeader(MessageTypeEnum.MESSAGE_ACK.getType());
        respHeader.trackHeader(reqHeader);
        message.setHeader(respHeader);
        message.setBody(messageAck);
        return message;
    }

    @SneakyThrows
    private static String extractUuId(String jsonStr) {
        JsonNode jsonTree = JacksonObjectMapper.getJsonTree(jsonStr);
        String uuid = null;
        if (jsonTree != null && jsonTree.get("uuid") != null) {
            uuid = jsonTree.get("uuid").textValue();
        }
        return uuid;
    }

    @Override
    public short getMessageType() {
        return MessageTypeEnum.MESSAGE.getType();
    }


    @Override
    public Message process(WebSocketSession session, Message messageFrame) {
        MessageTypeMessage message = (MessageTypeMessage) messageFrame.getBody();
        try {
            final boolean resp = longLinkImAdaptor.dispatchMessage(session.getUserId(), ((MessageTypeMessage) messageFrame.getBody()).getBody());
            if(resp){
                session.sendMessage(buildAck(null, messageFrame.getHeader(), extractUuId(new String(message.getBody()))));
            }
        } catch (Exception e) {
            log.error("MessageTypeProcessor process exception messageFrame={},session={}", messageFrame, session);
            session.sendMessage(buildAck(null, messageFrame.getHeader(), -1, SERVER_EXCEPTION, extractUuId(new String(message.getBody()))));

        }

        return buildSilenceAck(messageFrame.getHeader());
    }

    @Override
    protected MessageBody doParseBody(int contentStr, String msgBody) throws Exception {
        MessageTypeMessage message = new MessageTypeMessage();
        message.setBody(msgBody.getBytes(StandardCharsets.UTF_8));
        return message;
    }

    @Data
    public static class MessageTypeMessage implements MessageBody, Serializable {
        private byte[] body;
    }

    @Data
    public static class MessageTypeMessageAck extends RespMessageBody implements Serializable {
    }
}
